/*
 * memfiler.c
 * Part of the !Memphis distribution
 * (c) bdb/nas, 1991-7
 */

/* Developed by NAS from:
 * FSLib c.filer 3.1 93/03/09 20:00:45 brian Exp
 */

#define FS 	"Mem"
#define DISK 	"Sprites"
static char 	quitmsg[]="\0\0\0\0The data in the system sprite area will be lost if you closedown MemFS. Are you sure that you want to proceed?";
static char 	validstr[]="Smemfs";
static int 	sprx=43,spry=11;
static char 	RootName[]= FS"::"DISK".$";
#define RootName1 RootName
static int 	FilingSystemNumber=91; /* Acorn-allocated FS number */
/* #define KILLCMD1 "SNew" */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"
#include "ModuleWrap.h"
#include "util.h"
#include "cstart.h"
#include "rol_wimp.h"

#define RUNNABLE        /* to enable direct running */
#define TASK    ('K'<<24|'S'<<16|'A'<<8|'T')

/* FilerAction SWI calls */
#ifndef FilerAction_SendSelectedDirectory
#define FilerAction_SendSelectedDirectory       0x40f80
#define FilerAction_SendSelectedFile            0x40f81
#define FilerAction_SendStartOperation          0x40f82
#endif
#ifndef wimp_MFilerSelectionDirectory
#define wimp_MFilerSelectionDirectory           0x403
#define wimp_MFilerAddSelection                 0x404
#define wimp_MFilerAction                       0x405
#endif

int             taskhandle;
int             taskstack;
static int      wind_info = -1;
static int      wind_create = -1;
static char     workspace[650];
static BOOL     protection = FALSE;
static BOOL	predone = FALSE;

static int      filertaskhandle;
static char 	FilerName[]= FS"FSFiler";
static BOOL     dragging = FALSE;
static int      icondrag = 0;

/* Define TRACESERVICE in order to output trace of service calls */
/* #define TRACESERVICE */

static void removetask(void)
{
  _kernel_swi_regs r;

  r.r[0]=taskhandle;
  r.r[1]=TASK;
  taskhandle=0;
  if (r.r[0] && r.r[0]!=-1)
    _kernel_swi( XOS_Bit | Wimp_CloseDown , &r, &r );
  if (taskstack)
    free((char *)taskstack);
  taskstack=0;
}

/* RISC_OSLib wimp_starttask doesn't return task handle */
static int wimp_newtask(char *clicmd)
{
  _kernel_swi_regs r;

  r.r[0]=(int) clicmd;
  _kernel_swi( XOS_Bit | Wimp_StartTask , &r, &r );
  return(r.r[0]);
}

extern void protect_code(void);
static int finalise_privateword;

/*
 * This is the finalisation code
 */
static void fs_finalise(void)
{
  _kernel_swi_regs r;
  if (protection)
  {
    r.r[0] = 0x1F;
    r.r[1] = (int) &protect_code;
    r.r[2] = finalise_privateword;
    protection = FALSE;
    _kernel_swi( XOS_Bit | OS_Release, &r, &r );
  }
  removetask();
}

/*
 * This is the initialisation code
 */
_kernel_oserror *fs_initialise(char *cmd_tail, int podule_base, void *private_word)
{
  _kernel_oserror *err=NULL;

  private_word=private_word;
  finalise_privateword = (int) private_word;
  /*
   * These keep the compiler quiet.
   */
  cmd_tail = cmd_tail;
  podule_base = podule_base;

  /*
   * Must record fact filer task is not running
   */
  taskhandle = 0;
  taskstack = 0 ; /* and that its stack is not yet allocated */

  atexit( fs_finalise );

  return err;
}

/*
 * Service call handler
 */

#ifdef TRACESERVICE
static struct {int svc; char *name;} svcs[] =
{
  {0x00,"Serviced"},
  {0x04,"UKCommand"},
  {0x06,"Error"},
  {0x07,"UKByte"},
  {0x08,"UKWord"},
  {0x09,"Help"},
  {0x0b,"ReleaseFIQ"},
  {0x0c,"ClaimFIQ"},
  {0x11,"Memory"},
  {0x12,"StartUpFS"},
  {0x27,"Reset"},
  {0x28,"UKConfig"},
  {0x29,"UKStatus"},
  {0x2a,"NewApplication"},
  {0x40,"FSRedclare"},
  {0x41,"Print"},
  {0x42,"LookupFileType"},
  {0x43,"International"},
  {0x44,"Keyhandler"},
  {0x45,"PreReset"},
  {0x46,"ModeChange"},
  {0x47,"ClaimFIQinBackground"},
  {0x48,"ReAllocatePorts"},
  {0x49,"StartWimp"},
  {0x4a,"StartedWimp"},
  {0x4b,"StartFiler"},
  {0x4c,"StartedFiler"},
  {0x4d,"PreModeChange"},
  {0x4e,"MemoryMoved"},
  {0x4f,"FilerDying"},
  {0x50,"ModeExtension"},
  {0x51,"ModeTranslation"},
  {0x52,"MouseTrap"},
  {0x53,"WimpCloseDown"},
  {0x54,"Sound"},
  {0x55,"NetFS"},
  {0x56,"EconetDying"},
  {0x57,"WimpReportError"},
  {0x60,"ResourceFSStarting"},
  {-1,"Something else"}
};
#endif

void fs_service(int service_number, _kernel_swi_regs *r, void *private_word)
{
#ifdef TRACESERVICE
  int i;

  for (i=0; svcs[i].svc>=0; i++) if (svcs[i].svc==service_number) break;
  printf("Service_%s (%#x)%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\r\n",svcs[i].name,
        service_number,*r);
#endif
  private_word=private_word;
  switch( service_number )
  {
    case Service_StartFiler:
      if (!taskhandle)
      {
        filertaskhandle=r->r[0];
        taskhandle=-1; /* attempting start flag */
        r->r[0]=(int)("Desktop_"FS"FSFiler");
        r->r[1]=0;
      }
      break;
    case Service_StartedFiler:
      if (taskhandle==-1)
        taskhandle=0;
      break;
    case Service_Reset:
      taskhandle=0;
      protection=FALSE;
      break;
    case Service_FilerDying:
      removetask();
      break;
    /*
     * Handle other service calls here
     */
  }
}

/*
 * command processor
 */
_kernel_oserror *fs_command(char *arg_string, int argc, int cmd_no, void *private_word)
{
  _kernel_swi_regs r;
#define My_Command_Parameter_Buffer_Len 256
  static char my_command_parameter_buffer[ My_Command_Parameter_Buffer_Len ];
  char *temptr = my_command_parameter_buffer;

  argc = argc;
  private_word = private_word;

  /*
   * Change the control character terminator to a nul terminator
   */
  for ( ; temptr - my_command_parameter_buffer < My_Command_Parameter_Buffer_Len && *arg_string >= ' ' ; )
  {
    *temptr++ = *arg_string++;
  }

  *temptr = '\0';

  arg_string = my_command_parameter_buffer;

  /*
   * Switch between the commands
   */
  switch ( cmd_no )
  {
    case 0: /*      *Desktop_FSnameFSFiler */
      if (taskhandle!=-1)
      {
#ifndef RUNNABLE
        printf("Use *Desktop to start %s\n",FilerName);
        return NULL;
#else
        removetask();
        taskhandle=-1;
#endif
      }
      r.r[0] = OSModule_Enter;
      r.r[1] = (int)FilerName;
      r.r[2] = (int)arg_string;
      return _kernel_swi( XOS_Bit | OS_Module, &r, &r );
    case 1: /*      *MemProtect */
      if (protection) return NULL;
      r.r[0] = 0x1F;
      r.r[1] = (int) &protect_code;
      r.r[2] = (int)private_word;
      protection = TRUE;
      return _kernel_swi( XOS_Bit | OS_Claim, &r, &r );
    case 2: /*      *MemNormal*/
      if (!protection) return NULL;
      r.r[0] = 0x1F;
      r.r[1] = (int) &protect_code;
      r.r[2] = (int)private_word;
      protection = FALSE;
      return _kernel_swi( XOS_Bit | OS_Release, &r, &r );
    default:
      return NULL;
  }
}

int filertask(char *cmdtail);

#define MENUDEPTH 4

static struct
{
  wimp_menuhdr hdr;
  wimp_menuitem item[MENUDEPTH];
} mymenu=
{ { "Menutitle", 7, 2, 7, 0, 128, 44, 0 },
  {
    {   0,
        (wimp_menuptr) -1,
        wimp_ITEXT | wimp_IBTYPE*wimp_BNOTIFY | wimp_IFORECOL*7 | wimp_IBACKCOL*0,
        "Info"
    },
    {   0,
        (wimp_menuptr) -1,
        wimp_ITEXT | wimp_IBTYPE*wimp_BNOTIFY | wimp_IFORECOL*7 | wimp_IBACKCOL*0,
        "Create"
    },
    {   0,
        (wimp_menuptr) -1,
        wimp_ITEXT | wimp_IBTYPE*wimp_BNOTIFY | wimp_IFORECOL*7 | wimp_IBACKCOL*0,
        "Free"
    },
    {
        wimp_MLAST,
        (wimp_menuptr) -1,
        wimp_ITEXT | wimp_IBTYPE*wimp_BNOTIFY | wimp_IFORECOL*7 | wimp_IBACKCOL*0,
        "Quit"
    }
  }
};

/*
 * DragASprite routines
 */

#ifndef DragASprite_Start
#define DragASprite_Start       0x42400
#define DragASprite_Stop        0x42401
#endif

static os_error * drag_spritestart(int flags, void *area, char *name,
                        wimp_box b1, wimp_box b2)
{ _kernel_swi_regs r;
  os_error *e;

  r.r[0] = flags;
  r.r[1] = (int) area;
  r.r[2] = (int) name;
  r.r[3] = (int) &b1;
  r.r[4] = (int) &b2;
  e = (os_error *) _kernel_swi(XOS_Bit + DragASprite_Start, &r, &r);
  return(e);
}

static os_error * drag_spritestop(void)
{ _kernel_swi_regs r;
  os_error *e;

  e = (os_error *) _kernel_swi(XOS_Bit + DragASprite_Stop, &r, &r);
  return(e);
}

typedef struct {          /* icon description structure */
  wimp_w w;
  wimp_i i;
  wimp_box box;           /* bounding box - relative to
                           * window origin (work area top left) */
  wimp_iconflags flags;   /* word of flag bits defined above */
  wimp_icondata data;     /* union of bits & bobs as above */
} wimp_iconstr;

/*
 * Performs a simple xfersend() type operation upon dragging file icon
 */
static void ourxfersend(void)
{
  wimp_dragstr dr;
  wimp_wstate wstate;
  wimp_iconstr icon;
  wimp_w w = wind_create;
  wimp_mousestr mouse_str;
  int x_limit = 32768, y_limit = 32768;
  int screen_x0, screen_y0, mouse_x, mouse_y, x0, y0, x1, y1;
  _kernel_swi_regs r;
  os_error *err;
  int x, y;

  /* Wimp_GetPointerInfo */
  r.r[1] = (int) &mouse_str;
  err=(os_error *)_kernel_swi(Wimp_GetPointerInfo, &r, &r );
  mouse_x = mouse_str.x;
  mouse_y = mouse_str.y;

  /* Wimp_GetWindState */
  r.r[1] = (int) &wstate;
  wstate.o.w = mouse_str.w;
  err=(os_error *)_kernel_swi(Wimp_GetWindowState, &r, &r );
  screen_x0 = wstate.o.box.x0 - wstate.o.x;
  screen_y0 = wstate.o.box.y1 - wstate.o.y;

  /* Wimp_GetIconInfo */
  r.r[1] = (int) &icon;
  icon.w = mouse_str.w;
  icon.i = mouse_str.i;
  err=(os_error *)_kernel_swi(Wimp_GetIconState, &r, &r );

  /* Drag from iconbar */
  if (mouse_str.w == -2)
  {
    x0 = screen_x0 + icon.box.x0 - 8;
    y0 = screen_y0 + icon.box.y0 + 32;
    x1 = screen_x0 + icon.box.x1 + 8;
    y1 = screen_y0 + icon.box.y1 + 4;
    x = 0x80;                   /* Test for SHIFT key == move files */
    os_byte(121, &x, &y);
    if (x == 0) icondrag = 1;
      else icondrag = 2;
    x = 0x81;                   /* Test for CTRL key == change directory */
    os_byte(121, &x, &y);
    if (x == 255) icondrag = 3;
  } else
  {
    x0 = screen_x0 + icon.box.x0;
    y0 = screen_y0 + icon.box.y0;
    x1 = screen_x0 + icon.box.x1;
    y1 = screen_y0 + icon.box.y1;
    icondrag = 0;
  }

  /* RISC OS 3.00 or later, we have DragASprite */
  x = 0x1C; y = 0;
  os_byte(161, &x, &y);
  if ((y & 2) == 2)
  { char name[12];
    wimp_box b1, b2;
    if (icondrag < 3) strcpy(name, "memfs");
      else strcpy(name, "memfs_csd");
    if (icondrag == 0) strcpy(name, "file_3f1");
    /* DragASprite bit set, go for it ! */
    b1.x0 = x0; b1.x1 = x1;
    b1.y0 = y0; b1.y1 = y1;
    drag_spritestart(197, (void *) 1, name, b1, b2);
    dragging = TRUE;
  }
  else
  {
    /* Set up drag */
    dr.window    = w; /*not relevant*/
    dr.type      = wimp_USER_FIXED;
    dr.box.x0    = x0;
    dr.box.y0    = y0;
    dr.box.x1    = x1;
    dr.box.y1    = y1;
    dr.parent.x0 = x0 - mouse_x; /*Expanded parent by box overlap*/
    dr.parent.y0 = y0 - mouse_y;
    dr.parent.x1 = x1 - mouse_x + x_limit;
    dr.parent.y1 = y1 - mouse_y + y_limit;
    r.r[1] = (int) &dr;
    err=(os_error *)_kernel_swi(Wimp_DragBox, &r, &r );
    dragging = FALSE;
  }
}

/* --- Read from an indirected text icon --- */
static void wind_getstring(wimp_w window, wimp_i icon, char *text)
{ wimp_iconstr res;
  _kernel_swi_regs r;

  /* Get the current state of specified icon */
  r.r[1] = (int) &res;
  res.w = window;
  res.i = icon;
  _kernel_swi(Wimp_GetIconState, &r, &r );

  /* Read from indirected text buffer */
  strcpy(text, res.data.indirecttext.buffer);
}

/* --- Update an indirected text icon --- */
static void wind_setstring(wimp_w window, wimp_i icon, char *text)
{ wimp_iconstr     res;
  _kernel_swi_regs r;

  /* Get the current state of specified icon */
  r.r[1] = (int) &res;
  res.w = window;
  res.i = icon;
  _kernel_swi(Wimp_GetIconState, &r, &r );

  /* Write to indirected text buffer */
  strcpy(res.data.indirecttext.buffer, text);
}

/*
 * Sends out an appropriate DATASAVE message for creating a memdisc
 */
static void creatememdisc(int type)
{
  wimp_mousestr mousestr;
  wimp_msgstr msg;
  _kernel_swi_regs r;
  os_error *err;
  int i, tail;
  char name[256];

  /* Wimp_GetPointerInfo */
  r.r[1] = (int) &mousestr;
  err=(os_error *)_kernel_swi(Wimp_GetPointerInfo, &r, &r );

  if ((mousestr.w < 0) || (mousestr.w == wind_create)) return;  /* do nothing */
  msg.hdr.size = sizeof(wimp_msghdr) + sizeof(wimp_msgdatasave);
  msg.hdr.task = mousestr.w;
  msg.hdr.your_ref = 0;
  msg.hdr.action = wimp_MDATASAVE;
  msg.data.datasave.w = mousestr.w;
  msg.data.datasave.i = mousestr.i;
  msg.data.datasave.x = mousestr.x;
  msg.data.datasave.y = mousestr.y;
  msg.data.datasave.type = 0xB23;
  msg.data.datasave.estsize = 0;

  if (type == 0)
  {
    wind_getstring(wind_create, 2, (char *) &name);
    tail = strlen(name); /* point at the zero */
    while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':')
      tail--;

    for (i = 0; i <= 10; i++) msg.data.datasave.leaf[i] = name[tail++];
    msg.data.datasave.leaf[11] = '\0' ;     /* force termination */
  } else strcpy(msg.data.datasave.leaf, "x");

  err=wimp_sendwmessage(wimp_ESEND,&msg,mousestr.w, mousestr.i);
  err=wimp_create_menu((wimp_menustr *) -1,0,0);
}

/*
 * Checks dest path for missing "." before calling creatememdisc()
 */
static void precreatememdisc()
{
  char filename[256];
  BOOL dot = FALSE;
  os_error err;
  int i = 0;
  _kernel_swi_regs r;

  /* Check for name with no "." in it, and complain if so. */
  wind_getstring(wind_create, 2, (char *) &filename);
  while ((! dot) && filename[i] != 0) dot = (filename[i++] == '.');
  if (!dot)
  {
    err.errnum = 0;
    strcpy(err.errmess, "To save, drag the icon to a directory viewer.");
    wimp_reporterror(&err,0, FilerName);
  }
  else
  {
    char buf[256];
    FILE *f;

    f = fopen(filename, "r");
    if (f)
    {
      fclose(f);
      err.errnum = 0;
      strcpy(err.errmess, "File already exists.");
      wimp_reporterror(&err,0, FilerName);
    }
    else
    {
      sprintf(buf, "Create %s\n", filename);
      r.r[0] = (int) buf;
      _kernel_swi(OS_CLI, &r, &r );

      sprintf(buf, "SetType %s B23\n", filename);
      r.r[0] = (int) buf;
      _kernel_swi(OS_CLI, &r, &r );

      sprintf(buf, "Filer_OpenDir %s\n", filename);
      /* For some annoying reason (stack, workspace?) use of system() was causing
       * fatal crashes at program exit
       */
      /* r.r[0] = (int) buf;
      _kernel_swi(OS_CLI, &r, &r );
      strcpy(buf, "Do Filer_OpenDir Mem#|<ColonSemi>:$"); */
      r.r[0] = (int) buf;
      _kernel_swi(OS_CLI, &r, &r );
      wimp_create_menu((wimp_menustr *) -1,0,0);
    }
    wind_setstring(wind_create, 2, filename);
  }
}

/*
 * Delete any mfs* sprites in system sprite area
 */
static void wipespritearea(void)
{
  _kernel_swi_regs r;
  os_error *err;
  int nsprites, loop;
  char name[13];

  r.r[0] = 8;
  err=(os_error *)_kernel_swi(OS_SpriteOp, &r, &r );
  nsprites = r.r[3];
  if ((err) || (nsprites < 1) || (r.r[2] < 1)) return;

  _kernel_swi(Hourglass_On, &r, &r );
  loop = nsprites;
  do
  {
     r.r[0] = 13;
     r.r[2] = (int) &name;
     r.r[3] = 12;
     r.r[4] = loop;
     _kernel_swi(OS_SpriteOp, &r, &r );
     if ((name[0] = 'm') && (name[1] = 'f') && (name[2] = 's'))
     {
       r.r[0] = 25;
       r.r[2] = (int) &name;
       _kernel_swi(OS_SpriteOp, &r, &r );
     }
  } while ((loop--)>1);

  _kernel_swi(Hourglass_Off, &r, &r );
}

/*
 * Template open/load/close code
 */
static os_error *template(int osver)
{
  _kernel_swi_regs r;
  os_error *err;
  char path[] = "<Memphis$Dir>.Resources.Template3D";
  char name[12];
  char templates[512];
  int x, y;

  /* '3D-look' bit */
  x = 140; y = 0;
  os_byte(161, &x, &y);
  if (((y & 1) == 0) || (osver < 300))
  {
    strcpy(path, "<Memphis$Dir>.Resources.Templates");
  }

  r.r[1]=(int) path;
  err=(os_error *)_kernel_swi(Wimp_OpenTemplate, &r, &r );
  if (err) return(err);
  strcpy(name, "progInfo");
  r.r[1] = (int) templates;
  r.r[2] = (int) workspace;
  r.r[3] = (int) workspace + sizeof(workspace);
  r.r[4] = -1;
  r.r[5] = (int) name;
  r.r[6] = 0;
  err=(os_error *)_kernel_swi(Wimp_LoadTemplate, &r, &r );
  if (err) return(err);
  err=(os_error *)_kernel_swi(Wimp_CreateWindow, &r, &r );
  if (err) return(err);
  wind_info = r.r[0];
  strcpy(name, "xfer_make");
  r.r[6] = 0;
  err=(os_error *)_kernel_swi(Wimp_LoadTemplate, &r, &r );
  if (err) return(err);
  err=(os_error *)_kernel_swi(Wimp_CreateWindow, &r, &r );
  if (err) return(err);
  wind_create = r.r[0];
  err=(os_error *)_kernel_swi(Wimp_CloseTemplate, &r, &r );
  if (err) return(err);

  return(NULL);
}

/* --- RISC OS print with file handle rather than stream --- */
static void rofprint(int fh, char *text)
{ _kernel_osgbpb_block b;

  b.dataptr = text;
  b.nbytes = strlen( text );
  _kernel_osgbpb( 2, fh, &b );
}

int filertask(char *cmdtail)
{
  _kernel_swi_regs r;
  os_error *err;
  wimp_icreate wi;
  wimp_i icon;
  wimp_eventstr ev;
  wimp_mousestr m;
  int wimpversion;
  int maydataload=0;

#ifndef RUNNABLE
  if (taskhandle!=-1)
    return 0;
#endif
  cmdtail=cmdtail; /* Use it to scare off warnings */
  r.r[0]=402;
  r.r[1]=TASK;
  r.r[2]=(int) "MemFS Filer";
  r.r[3]=-1;
  err=(os_error *)_kernel_swi( Wimp_Initialise, &r, &r );
  if (err)
    goto error;
  wimpversion=r.r[0];
  taskhandle=r.r[1];
  if (wimpversion>200)
    wi.w=-6, r.r[0]=0x3F000000;
  else
    wi.w=-2;
  wi.i.box.x0=0;
  wi.i.box.y0=-16; /* base of text, 32 high */
  wi.i.box.x1=2*sprx;
  wi.i.box.y1=-16+32+4+4*spry;
//  wi.i.box.x1=34;
//  wi.i.box.y1=-34; // paul - you're a twit!
  wi.i.flags=wimp_ITEXT |
             wimp_ISPRITE |
             wimp_IHCENTRE |
             wimp_INDIRECT |
             wimp_IBTYPE*wimp_BDEBOUNCEDRAG |
             wimp_IFORECOL*7 |
             wimp_IBACKCOL*1 ;
  wi.i.data.indirecttext.buffer=FS;
  wi.i.data.indirecttext.validstring=validstr;
  wi.i.data.indirecttext.bufflen=3;
  r.r[1]=(int)&wi;
  err=(os_error *)_kernel_swi( Wimp_CreateIcon, &r, &r );
  icon=r.r[0];
  if (err)
    goto error;
  err=(os_error *)template(wimpversion);
  if (err)
    goto error;

  for (;;)
  {
    maydataload = 0;
pol:err=wimp_poll(wimp_EMNULL,&ev);
    if (err)
      goto error;
    switch (ev.e)
    {
      case wimp_EOPEN:
        err=wimp_open_wind(&ev.data.o);
        continue;

      case wimp_EBUT:
        if (ev.data.but.m.i == icon)
        {
          /* wimp_mousestr m2; */
          switch (ev.data.but.m.bbits)
          {
            case wimp_BLEFT:
            /* case wimp_BRIGHT: */
              ev.data.msg.hdr.size=sizeof(wimp_msghdr)+sizeof(int)*2+
                  (strlen(RootName)&~3)+4;
              ev.data.msg.hdr.your_ref=0;
              ev.data.msg.hdr.action=wimp_FilerOpenDir;
              ev.data.msg.data.words[0]=FilingSystemNumber;
              ev.data.msg.data.words[1]=0;
              strcpy((char *)&ev.data.msg.data.words[2],
                  ev.data.but.m.bbits==wimp_BLEFT?RootName:RootName1 );
              /* r.r[1] = (int) &m2;
              err=(os_error *)_kernel_swi(Wimp_GetPointerInfo, &r, &r );
              if (m2.bbits != 0) continue;  */
              err=wimp_sendmessage(wimp_ESEND,&ev.data.msg,(wimp_t)filertaskhandle);
              if (err)
                goto error;
              continue;
            case wimp_BMID:
              strcpy(mymenu.hdr.title,FS"FS");
              mymenu.item[0].submenu = (wimp_menuptr) wind_info;
              mymenu.item[1].submenu = (wimp_menuptr) wind_create;
              err=wimp_create_menu((wimp_menustr *)&mymenu,ev.data.but.m.x-64,
                  96+MENUDEPTH*44);
              if (err)
                goto error;
              continue;
            case wimp_BDRAGLEFT:
            case wimp_BDRAGRIGHT:
              ourxfersend();    /* Drag icon on iconbar */
              continue;
            default:
              continue;
          }
        }
        if ((ev.data.but.m.i == 0) && (ev.data.but.m.w == wind_create))
        {
          precreatememdisc();
        }
        if ((ev.data.but.m.i == 1) && (ev.data.but.m.w == wind_create))
        {
          switch (ev.data.but.m.bbits)
          {
            case wimp_BLEFT:
              wimp_create_menu((wimp_menustr *) -1,0,0);
              break;
            default:
              break;
          }
        }
        if ((ev.data.but.m.i == 3) && (ev.data.but.m.w == wind_create))
        {
          switch (ev.data.but.m.bbits)
          {
            case wimp_BDRAGLEFT:
            case wimp_BDRAGRIGHT:
              ourxfersend();   /* Drag from saveas() dbox */
              continue;
            default:
             continue;
          }
        }
        continue;
      break;

    case wimp_EMENU:
      switch (ev.data.menu[0])
      {
        case 0: /* Info */
          break;
        case 1: /* Create */
          break;
        case 2: /* Free */
          if (_kernel_oscli("ShowFree -fs "FS" "DISK)==_kernel_ERROR)
                _kernel_oscli("WimpTask "FS":Free "DISK);
          break;
        case 3: /* Quit */
          r.r[0]=17;
          r.r[1]=(int)&RootName;
          if (!_kernel_swi( OS_File, &r, &r ) && r.r[4] )
          {
            r.r[0]=(int)&quitmsg;
            r.r[1]=3+(1<<4);
            r.r[2]=(int)FilerName;
            err=(os_error *)_kernel_swi( Wimp_ReportError, &r, &r );
            if (r.r[1]!=1)
              continue;
          }
          r.r[1] = 0x7D;
          r.r[2] = (int) FS"::"DISK"";
          _kernel_swi( OS_ServiceCall, &r, &r );
          _kernel_oscli("RMKill "FS"FS");
#ifdef KILLCMD1
          _kernel_oscli(KILLCMD1);
#else
          wipespritearea();
#endif
          r.r[0]=3;
          r.r[1]=-4<<20;
          _kernel_swi( OS_ChangeDynamicArea, &r, &r );
          r.r[0]=0;
          r.r[3]=(int)&FilerName;
          _kernel_swi( OS_ExitAndDie, &r, &r );
      }
      r.r[1]=(int)&m;
      _kernel_swi(Wimp_GetPointerInfo, &r, &r );
      if (m.bbits == wimp_BRIGHT)
      {
        err=wimp_create_menu((wimp_menustr *)&mymenu,m.x, m.y);
        if (err) goto error;
      }
      continue;

    case wimp_EKEY:
      if ((ev.data.key.c.w == wind_create) && (ev.data.key.chcode == 13))
      {
        precreatememdisc();
      } else
      {
        r.r[0] = ev.data.key.chcode;
        _kernel_swi( Wimp_ProcessKey, &r, &r );
      }
      continue;

    case wimp_EUSERDRAG:
      if (dragging)
      {
        /* Clean up DragASprite workspace */
        drag_spritestop();
        dragging = FALSE;
      }
      if (icondrag == 0) creatememdisc(0);
        else creatememdisc(1);
      continue;

    case wimp_ESEND:
    case wimp_ESENDWANTACK:
      switch (ev.data.msg.hdr.action)
      {
        char buf[256];

        case wimp_MCLOSEDOWN:
          break;
        case wimp_MPREQUIT:
          if (predone) goto pol;
          r.r[0]=17;
          r.r[1]=(int)&RootName;
          if (!_kernel_swi( OS_File, &r, &r) && r.r[4])
          {
            int task = ev.data.msg.hdr.task;

            ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
            wimp_sendmessage(wimp_EACK,&ev.data.msg,task);
            r.r[0]=(int) &quitmsg;
            r.r[1]=3+(1<<4);
            r.r[2]=(int) FilerName;
            err = (os_error *) _kernel_swi(Wimp_ReportError, &r, &r);
            if (r.r[1] != 1) goto pol;
            /* Restart PreQuit broadcast (actually a key press event !) */
            predone = TRUE;
            ev.data.key.chcode = 0x1FC;
            wimp_sendmessage(wimp_EKEY,&ev.data.msg,task);
          }
          goto pol;
        case wimp_MDATASAVE:
          strcpy(buf,RootName);
          strcat(buf,".");
          strcat(buf,ev.data.msg.data.datasaveok.name);
          strcpy(ev.data.msg.data.datasaveok.name,buf);
          ev.data.msg.hdr.size = (strlen(ev.data.msg.data.datasaveok.name)|3)+1+44;
          ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
          ev.data.msg.hdr.action = wimp_MDATASAVEOK;
          wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
          maydataload = 1;
          goto pol;
        case wimp_MDATASAVEOK:
          if (strcmp(ev.data.msg.data.datasaveok.name, "<Wimp$Scrap>") == 0) goto pol;
          if (icondrag == 0)
          {
            FILE *f;
            os_error err;

            f = fopen(ev.data.msg.data.datasaveok.name, "r");
            if (f)
            {
              fclose(f);
              err.errnum = 0;
              strcpy(err.errmess, "File already exists.");
              wimp_reporterror(&err,0, FilerName);
            }
            else
            {
              sprintf(buf, "Create %s\n",ev.data.msg.data.datasaveok.name);
              r.r[0] = (int) buf;
              _kernel_swi(OS_CLI, &r, &r );

              sprintf(buf, "SetType %s B23\n", ev.data.msg.data.datasaveok.name);
              r.r[0] = (int) buf;
              _kernel_swi(OS_CLI, &r, &r );

              sprintf(buf, "Filer_OpenDir %s\n", ev.data.msg.data.datasaveok.name);
              r.r[0] = (int) buf;
              _kernel_swi(OS_CLI, &r, &r );
            }
            /* strcpy(buf, "Do Filer_OpenDir Mem#|<ColonSemi>:$");
            r.r[0] = (int) buf;
            _kernel_swi(OS_CLI, &r, &r ); */
            wind_setstring(wind_create, 2, ev.data.msg.data.datasaveok.name);
            ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
            ev.data.msg.hdr.action = wimp_MDATALOAD;
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
          }
          else
          {
            if (icondrag == 3)
            { int p;
              sprintf(buf, "Dir %s\n", ev.data.msg.data.datasaveok.name);
              p = strlen(buf);
              buf[p-2] = '\0'; buf[p-3] = '\0';
              r.r[0] = (int) buf;
              _kernel_swi(OS_CLI, &r, &r );
              _kernel_swi(OS_WriteI+7, &r, &r );
              ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
              ev.data.msg.hdr.action = wimp_MDATALOAD;
              wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
            } else
            {
              int handle = wimp_newtask("Filer_Action");
              int tail;
              int rename;
              char dir[256];

              if (handle == 0) goto pol;
              /* Send ack to application (filer) */
              ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
              ev.data.msg.hdr.action = wimp_MDATASAVEOK;
              wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);

              if (icondrag == 2) rename = 6;
                else rename = 0;
              tail = strlen(ev.data.msg.data.datasaveok.name);
              strncpy(dir, ev.data.msg.data.datasaveok.name, tail-2);
              dir[tail-2] = '\0';

              ev.data.msg.hdr.your_ref = 0;
              ev.data.msg.hdr.action = wimp_MFilerSelectionDirectory;
              sprintf((char *) &ev.data.msg.data.words[0], "%s::%s.$\0", FS, DISK);
              wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);

              /* Add file selection (tricky!) */
              ev.data.msg.hdr.your_ref = 0;
              ev.data.msg.hdr.action = wimp_MFilerAddSelection;
              r.r[0] = 9;
              r.r[1] = (int) "Mem::Sprites.$";
              r.r[2] = (int) &ev.data.msg.data.words[0];
              r.r[3] = 1; r.r[4] = 0;
              r.r[5] = 64; r.r[6] = 0;
              do
              {
                _kernel_swi(OS_GBPB, &r, &r );
                if (r.r[3] != 0) wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);
              } while (r.r[4] != -1);

              ev.data.msg.data.words[0] = rename;
              ev.data.msg.data.words[1] = 1;
              strcpy((char *) &ev.data.msg.data.words[2], dir);
              ev.data.msg.hdr.your_ref = 0;
              ev.data.msg.hdr.action = wimp_MFilerAction;
              wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);
            }
            icondrag = 0;
          }
          goto pol;
        case wimp_MDATALOAD:
          if (maydataload)
          {
            /* Load from application */
            ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
            ev.data.msg.hdr.action = wimp_MDATALOADOK;
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);
            maydataload = 0;
          } else
          {
            int handle = wimp_newtask("Filer_Action");
            int tail;
            int x, y, rename;
            char dir[256];
            char leaf[32];
            char *name = ev.data.msg.data.dataload.name;

            /* Load from file/directory
               Setup some cunning filer_action move/copy action with messages */

            if (handle == 0) goto pol;
            /* Send ack to application (filer) */
            ev.data.msg.hdr.your_ref = ev.data.msg.hdr.my_ref;
            ev.data.msg.hdr.action = wimp_MDATALOADOK;
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,ev.data.msg.hdr.task);

            x = 0x80;                   /* Test for SHIFT key == move files */
            os_byte(121, &x, &y);
            rename = x ? 1 : 0;

            tail = strlen(name);
            while (tail > 0 && name[tail-1] != '.' && name[tail-1] != ':') tail--;
            strncpy(dir, name, tail-1);
            dir[tail-1] = '\0';
            strcpy(leaf, &name[tail]);

            ev.data.msg.hdr.your_ref = 0;
            ev.data.msg.hdr.action = wimp_MFilerSelectionDirectory;
            strcpy((char *) &ev.data.msg.data.words[0], dir);
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);

            ev.data.msg.hdr.your_ref = 0;
            ev.data.msg.hdr.action = wimp_MFilerAddSelection;
            strcpy((char *) &ev.data.msg.data.words[0], leaf);
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);

            ev.data.msg.data.words[0] = rename;
            ev.data.msg.data.words[1] = 1;
            sprintf((char *) &ev.data.msg.data.words[2], "%s::%s.$\0", FS, DISK);
            ev.data.msg.hdr.your_ref = 0;
            ev.data.msg.hdr.action = wimp_MFilerAction;
            wimp_sendmessage(wimp_ESEND,&ev.data.msg,handle);
          }
          continue;
        case wimp_MDATALOADOK:
          /* Redundant stage - we don't care if receiver died or not */
          continue;
        case wimp_SAVEDESK:     /* RISC OS 3.xx 'Desktop save' feature */
          {
            int fh = ev.data.msg.data.savedesk.filehandle;
            char command[256];
            char buf[256];
            char *path;
            int nsprites;

            r.r[0] = 8;
            err=(os_error *)_kernel_swi(OS_SpriteOp, &r, &r );
            nsprites = r.r[3];
            if ((err) || (nsprites < 1) || (r.r[2] < 1)) nsprites = 0;
            r.r[0] = (int) "Memphis$Dir";
            r.r[1] = (int) &buf;
            r.r[2] = 255;
            r.r[3] = 0; r.r[4] = 0;
            _kernel_swi( OS_ReadVarVal, &r, &r );
            buf[(r.r[2])] = '\0';

            path = (char *) r.r[1];
            if (path == NULL) continue;
            if (nsprites > 0)
            {
              wimp_starttask("SSave <Memphis$Dir>.SavedSpr");
              sprintf(command, "SLoad %s.SavedSpr\n", path);
              rofprint(fh, command);
            }
            sprintf(command, "/%s\n", path);
            rofprint(fh, command);
          }
          continue;

        default:
          continue;
      }
      break;

    default:
      continue;
    }
    break;
  }
  return 0;

error:
  wimp_reporterror(err,0, FilerName);
  return (int)err;
}
